package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/smart-snapshotter/pkg/loader"
	"github.com/smart-snapshotter/pkg/types"
)

// SimpleStorageBackend implements a basic storage backend for demonstration
type SimpleStorageBackend struct {
	data map[string][]byte
}

func NewSimpleStorageBackend() *SimpleStorageBackend {
	return &SimpleStorageBackend{
		data: make(map[string][]byte),
	}
}

func (s *SimpleStorageBackend) StoreFile(ctx context.Context, hash string, data []byte) error {
	s.data[hash] = data
	return nil
}

func (s *SimpleStorageBackend) LoadFile(ctx context.Context, hash string) ([]byte, error) {
	data, exists := s.data[hash]
	if !exists {
		return nil, fmt.Errorf("file not found: %s", hash)
	}
	return data, nil
}

func (s *SimpleStorageBackend) DeleteFile(ctx context.Context, hash string) error {
	delete(s.data, hash)
	return nil
}

func (s *SimpleStorageBackend) FileExists(ctx context.Context, hash string) (bool, error) {
	_, exists := s.data[hash]
	return exists, nil
}

func (s *SimpleStorageBackend) StoreBlock(ctx context.Context, hash string, data []byte) error {
	return s.StoreFile(ctx, hash, data)
}

func (s *SimpleStorageBackend) LoadBlock(ctx context.Context, hash string) ([]byte, error) {
	return s.LoadFile(ctx, hash)
}

func (s *SimpleStorageBackend) DeleteBlock(ctx context.Context, hash string) error {
	return s.DeleteFile(ctx, hash)
}

func (s *SimpleStorageBackend) BlockExists(ctx context.Context, hash string) (bool, error) {
	return s.FileExists(ctx, hash)
}

func (s *SimpleStorageBackend) StoreMetadata(ctx context.Context, key string, metadata []byte) error {
	return s.StoreFile(ctx, key, metadata)
}

func (s *SimpleStorageBackend) LoadMetadata(ctx context.Context, key string) ([]byte, error) {
	return s.LoadFile(ctx, key)
}

func (s *SimpleStorageBackend) DeleteMetadata(ctx context.Context, key string) error {
	return s.DeleteFile(ctx, key)
}

func (s *SimpleStorageBackend) Health(ctx context.Context) error {
	return nil
}

// SimpleCache implements a basic cache for demonstration
type SimpleCache struct {
	data map[string][]byte
}

func NewSimpleCache() *SimpleCache {
	return &SimpleCache{
		data: make(map[string][]byte),
	}
}

func (c *SimpleCache) Get(ctx context.Context, key string) ([]byte, error) {
	data, exists := c.data[key]
	if !exists {
		return nil, fmt.Errorf("cache miss: %s", key)
	}
	return data, nil
}

func (c *SimpleCache) Set(ctx context.Context, key string, value []byte, ttl time.Duration) error {
	c.data[key] = value
	return nil
}

func (c *SimpleCache) Delete(ctx context.Context, key string) error {
	delete(c.data, key)
	return nil
}

func (c *SimpleCache) Exists(ctx context.Context, key string) (bool, error) {
	_, exists := c.data[key]
	return exists, nil
}

func (c *SimpleCache) Clear(ctx context.Context) error {
	c.data = make(map[string][]byte)
	return nil
}

func (c *SimpleCache) GetStats(ctx context.Context) (types.CacheStats, error) {
	return types.CacheStats{
		Hits:      0,
		Misses:    0,
		Evictions: 0,
		Size:      int64(len(c.data)),
		Capacity:  1024 * 1024, // 1MB
		HitRatio:  0.0,
	}, nil
}

func main() {
	fmt.Println("Smart Loader Example")
	fmt.Println("====================")

	// Create storage and cache
	storage := NewSimpleStorageBackend()
	cache := NewSimpleCache()

	// Configure the smart loader
	config := types.LoaderConfig{
		PrefetchEnabled: true,
		PrefetchDepth:   3,
		MaxConcurrency:  10,
		Timeout:         30 * time.Second,
	}

	// Create smart loader
	smartLoader, err := loader.NewSmartLoader(config, storage, cache)
	if err != nil {
		log.Fatalf("Failed to create smart loader: %v", err)
	}

	// Start the loader
	if err := smartLoader.Start(); err != nil {
		log.Fatalf("Failed to start smart loader: %v", err)
	}
	defer smartLoader.Stop()

	ctx := context.Background()

	// Example 1: Basic loading with caching
	fmt.Println("\n1. Basic Loading and Caching")
	fmt.Println("----------------------------")

	// Store some test data
	testFiles := map[string][]byte{
		"config/app.json":     []byte(`{"name": "MyApp", "version": "1.0.0"}`),
		"data/users.json":     []byte(`[{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]`),
		"templates/index.html": []byte(`<html><body>Hello World!</body></html>`),
		"lib/utils.js":        []byte(`function helper() { return "utility function"; }`),
	}

	for key, data := range testFiles {
		if err := storage.StoreFile(ctx, key, data); err != nil {
			log.Printf("Failed to store %s: %v", key, err)
			continue
		}
	}

	// Load files and measure performance
	fmt.Println("Loading files...")
	start := time.Now()

	for key := range testFiles {
		data, err := smartLoader.Load(ctx, key)
		if err != nil {
			log.Printf("Failed to load %s: %v", key, err)
			continue
		}
		fmt.Printf("✓ Loaded %s (%d bytes)\n", key, len(data))
	}

	firstLoadTime := time.Since(start)
	fmt.Printf("First load completed in %v\n", firstLoadTime)

	// Load same files again (should be cached)
	fmt.Println("\nLoading same files again (should hit cache)...")
	start = time.Now()

	for key := range testFiles {
		data, err := smartLoader.Load(ctx, key)
		if err != nil {
			log.Printf("Failed to load %s: %v", key, err)
			continue
		}
		fmt.Printf("✓ Loaded %s from cache (%d bytes)\n", key, len(data))
	}

	secondLoadTime := time.Since(start)
	fmt.Printf("Second load completed in %v\n", secondLoadTime)

	// Example 2: Prefetch functionality
	fmt.Println("\n2. Prefetch Functionality")
	fmt.Println("------------------------")

	// Store related files
	relatedFiles := map[string][]byte{
		"images/photo_1.jpg": []byte("image data 1"),
		"images/photo_2.jpg": []byte("image data 2"),
		"images/photo_3.jpg": []byte("image data 3"),
	}

	for key, data := range relatedFiles {
		if err := storage.StoreFile(ctx, key, data); err != nil {
			log.Printf("Failed to store %s: %v", key, err)
			continue
		}
	}

	// Load one file to trigger prefetch
	fmt.Println("Loading photo_1.jpg to trigger prefetch...")
	_, err = smartLoader.Load(ctx, "images/photo_1.jpg")
	if err != nil {
		log.Printf("Failed to load photo_1.jpg: %v", err)
	}

	// Wait for prefetch to work
	time.Sleep(200 * time.Millisecond)

	// Check stats
	stats, err := smartLoader.GetStats(ctx)
	if err != nil {
		log.Printf("Failed to get stats: %v", err)
	} else {
		fmt.Printf("Loader stats: %+v\n", stats)
	}

	// Example 3: Priority-based loading
	fmt.Println("\n3. Priority-based Loading")
	fmt.Println("-------------------------")

	// Create priority manager and demonstrate priority calculation
	priorityManager := loader.NewPriorityManager()

	// Simulate file access events
	files := []string{
		"/bin/ls",                    // System executable - high priority
		"/etc/config.conf",          // Config file - high priority
		"/usr/lib/libtest.so",       // Library - high priority
		"/home/user/document.txt",   // User file - normal priority
		"/tmp/tempfile.tmp",         // Temp file - low priority
	}

	for _, file := range files {
		event := loader.FileEvent{
			Path:      file,
			EventType: loader.FileAccess,
			PID:       1234,
			Timestamp: time.Now().Unix(),
		}

		priority := priorityManager.CalculatePriority(file, event)
		fmt.Printf("File: %-30s Priority: %.2f\n", file, priority)
	}

	// Example 4: Progress tracking
	fmt.Println("\n4. Progress Tracking")
	fmt.Println("--------------------")

	// Load a file and check progress
	progress, err := smartLoader.GetProgress(ctx, "config/app.json")
	if err != nil {
		log.Printf("Failed to get progress: %v", err)
	} else {
		fmt.Printf("Progress for config/app.json: %+v\n", progress)
	}

	// Example 5: Fanotify monitoring (if available)
	fmt.Println("\n5. Fanotify Monitoring")
	fmt.Println("---------------------")

	if loader.IsFanotifyAvailable() {
		fmt.Println("✓ Fanotify is available on this system")

		// Add a watch for demonstration
		watchPath := "/tmp"
		if err := smartLoader.AddWatch(watchPath); err != nil {
			log.Printf("Failed to add watch for %s: %v", watchPath, err)
		} else {
			fmt.Printf("✓ Added watch for %s\n", watchPath)

			// Remove the watch
			if err := smartLoader.RemoveWatch(watchPath); err != nil {
				log.Printf("Failed to remove watch for %s: %v", watchPath, err)
			} else {
				fmt.Printf("✓ Removed watch for %s\n", watchPath)
			}
		}
	} else {
		fmt.Println("✗ Fanotify is not available on this system")
		fmt.Println("  This is normal for development environments or older kernels")
	}

	// Final statistics
	fmt.Println("\n6. Final Statistics")
	fmt.Println("-------------------")

	finalStats, err := smartLoader.GetStats(ctx)
	if err != nil {
		log.Printf("Failed to get final stats: %v", err)
	} else {
		fmt.Printf("Total requests: %d\n", finalStats.TotalRequests)
		fmt.Printf("Cache hits: %d\n", finalStats.CacheHits)
		fmt.Printf("Cache misses: %d\n", finalStats.CacheMisses)
		fmt.Printf("Prefetch requests: %d\n", finalStats.PrefetchRequests)
		fmt.Printf("Total bytes loaded: %d\n", finalStats.TotalBytesLoaded)
		fmt.Printf("Average load time: %v\n", finalStats.AverageLoadTime)
	}

	fmt.Println("\n✓ Smart loader example completed successfully!")
}